/* 实现温湿度检测功能
 * io 为 d13 对应 p0.4
 * range temp:-20~+60℃    humd:5~95%RH
 */

#include "dht11.h"
#include <drv_gpio.h>
#include <string.h>
#include <stdio.h>

/* 全局变量定义 */
rt_uint8_t temperature, temperature_x, humidity, humidity_x;
rt_thread_t dht11_thread = RT_NULL;

/* 毫秒级延时函数（忙等待，不依赖调度器） */
void dht11_delay_ms(rt_uint32_t ms)
{
    rt_tick_t start = rt_tick_get();
    rt_tick_t delay_ticks = rt_tick_from_millisecond(ms);
    while (rt_tick_get() - start < delay_ticks);
}

/* 微秒级延时函数（忙等待，不依赖调度器） */
void dht11_delay_us(rt_uint32_t us)
{
    rt_uint32_t i;
    for (i = 0; i < us; i++) {
        __NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();
    }
}

/* 复位DHT11 */
void dht11_reset(void)
{
    /* 设置为输出模式 */
    rt_pin_mode(DHT11_PIN, PIN_MODE_OUTPUT);

    /* 拉低至少18ms（使用忙等待延时，不依赖调度器） */
    rt_pin_write(DHT11_PIN, PIN_LOW);
    dht11_delay_ms(20);

    /* 拉高20-40us */
    rt_pin_write(DHT11_PIN, PIN_HIGH);
    dht11_delay_us(30);
}

/* 检查DHT11响应 */
rt_uint8_t dht11_check(void)
{
    rt_uint8_t retry = 0;

    /* 设置为输入模式 */
    rt_pin_mode(DHT11_PIN, PIN_MODE_INPUT_PULLUP);
    dht11_delay_us(40);

    /* 等待DHT11响应 */
    while (rt_pin_read(DHT11_PIN) == PIN_HIGH && retry < 100) {
        retry++;
        dht11_delay_us(1);
    }

    if (retry >= 100) return 1;  /* 响应超时 */

    retry = 0;

    /* 等待DHT11释放总线 */
    while (rt_pin_read(DHT11_PIN) == PIN_LOW && retry < 100) {
        retry++;
        dht11_delay_us(1);
    }

    if (retry >= 100) return 1;  /* 释放超时 */

    return 0;  /* 响应正常 */
}

/* 读取一个位 */
rt_uint8_t dht11_read_bit(void)
{
    rt_uint8_t retry = 0;

    /* 等待低电平结束 */
    while (rt_pin_read(DHT11_PIN) == PIN_HIGH && retry < 100) {
        retry++;
        dht11_delay_us(1);
    }

    if (retry >= 100) {
        return 1;
    }

    retry = 0;

    /* 等待高电平结束 */
    while (rt_pin_read(DHT11_PIN) == PIN_LOW && retry < 100) {
        retry++;
        dht11_delay_us(1);
    }

    if (retry >= 100) {
        rt_kprintf("lotl\n");
        return 1;
    }

    /* 延时110us判断数据位 */
    dht11_delay_us(110);

    /* 判断此时引脚状态 */
    return (rt_pin_read(DHT11_PIN) == PIN_HIGH) ? 1 : 0;
}

/* 读取一个字节 */
rt_uint8_t dht11_read_byte(void)
{
    rt_uint8_t i, byte = 0;

    for (i = 0; i < 8; i++) {
        byte <<= 1;
        byte |= dht11_read_bit();
    }

    return byte;
}

/* 读取DHT11数据 */
rt_uint8_t dht11_read_data(rt_uint8_t *temperature, rt_uint8_t *temperature_x,
                          rt_uint8_t *humidity, rt_uint8_t *humidity_x)
{
    rt_uint8_t buf[5];
    rt_uint8_t i;

    /* 复位DHT11 */
    dht11_reset();

    /* 检查DHT11响应 */
    if (dht11_check() != 0) {
        rt_kprintf("DHT11 not found!\n");
        return 1;
    }

    /* 读取40位数据 */
    for (i = 0; i < 5; i++) {
        buf[i] = dht11_read_byte();
    }

    /* 检查校验和 */
    if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]) {
        *humidity = buf[0];
        *humidity_x = buf[1];
        *temperature = buf[2];
        *temperature_x = buf[3];
        return 0;
    } else {
        return 1;
    }
}

/* DHT11数据采集线程入口函数 */
static void dht11_thread_entry(void *parameter)
{
    rt_err_t ret;

    /* 初始化DHT11引脚 */
    rt_pin_mode(DHT11_PIN, PIN_MODE_INPUT_PULLUP);
    rt_thread_mdelay(2000);  /* 等待DHT11稳定 */

    while (1) {
        rt_pin_mode(DHT11_PIN, PIN_MODE_INPUT_PULLUP);
        rt_thread_mdelay(500);  /* 等待DHT11稳定 */

        ret = dht11_read_data(&temperature, &temperature_x, &humidity, &humidity_x);
        if (ret == 0) {
        } else {
            rt_kprintf("DHT failed\n");
        }
        rt_thread_mdelay(DHT11_period_time);
    }
}

/* DHT11设备初始化函数 */
int dht11_device_init(void)
{
    /* 创建DHT11数据采集线程 */
    dht11_thread = rt_thread_create("dht11",
                                    dht11_thread_entry,
                                    RT_NULL,
                                    DHT11_THREAD_STACK_SIZE,
                                    DHT11_THREAD_PRIORITY,
                                    DHT11_THREAD_TIMESLICE);

    /* 创建成功则启动线程 */
    if (dht11_thread != RT_NULL) {
        rt_thread_startup(dht11_thread);
        return RT_EOK;
    } else {
        return RT_ERROR;
    }
}

/* 使用组件初始化机制自动初始化DHT11设备 */
INIT_DEVICE_EXPORT(dht11_device_init);
